home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-03-21 | 10.4 KB | 269 lines | [TEXT/MMCC] |
- /*
- WindowToEPS.c
- Copyright © 1994,1995 Denis G. Pelli
-
-
- WindowToEPS(window,filename,rectPtr,pageRectPtr,cellsPerInch,grayLevels,reflectance);
-
- This is a simple, but reasonably general, routine to convert a
- grayscale image (in window or GWorld) to a PostScript file that may be
- transmitted to a LaserWriter or Linotype to produce a halftone image on
- paper. We use it a lot, and it works well.
- The filename, by convention, should end in ".eps" to indicate that
- it is an encapsulated postscript file, but this is not enforced. The
- file's type is set to 'TEXT' with creator 'EPSF'. It's a plain text
- file.
- The PixMap must have 8 bits per pixel. The window's color table is
- ignored. The raw pixel value (which Apple calls an "index") is
- transformed by the optional reflectance array (if present), and then
- sent directly to the printer. If "reflectance" is NULL, then the pixel
- value, from 0 to 255 is interpreted by PostScript as proportional to
- desired reflectance, from zero to 1. If you supply a "reflectance" array
- the values should range from 0.0 to 1.0. The *rectPtr indicates what
- part of your PixMap is to be used.
- The *pageRectPtr is subtle. It describes, in typographers points
- (1/72"), the rectangle that your image will be mapped onto on the
- printed page. It is essential that you keep in mind that Apple and Adobe
- use different coordinate systems. Both Apple and Adobe increase x from
- left to right. However, Apple has y increasing from top to bottom,
- whereas Adobe increases y from bottom to top. Adobe's origin is the
- lower left corner of the page, even though that point is usually not
- printable, since most printers can only print to within about a half
- inch of the edge. The pageRect, though supplied in Apple's Rect data
- structure, must be in Adobe's coordinates, respecting the names of the
- Rect structure's fields: left, top, right, bottom. So, for an image to
- fill most of an 8.5x11 page, with 0.5" margins, you might use the
- following:
-
- SetRect(&pageRect,0.5*72,10.5*72,8*72,0.5*72);
-
- In printing PostScript halftones the halftone cell size determines
- both the spatial and graylevel resolutions of the resulting image. For
- the convenience of the user this can be specified by setting either the
- cellsPerInch or the grayLevels argument to the desired value; the other
- one should be zero. If both are zero then the printer will be left at
- its default cell size, which is usually a good choice. Note that there
- need not be any particular correspondence between pixels in your image
- and cells in the halftone; the printer automatically resamples your
- image to produce the halftone.
- If you set cellsPerInch to a nonzero value then the printer will be
- asked to print its halftone with that many halftone cells per inch. E.g.
- to produce a halftone original for subsequent one-to-one reproduction in
- a journal, you'll want the cells to be coarse enough for them to
- reproduce without re-screening, e.g. 100 cells per inch.
- Alternatively, if you set grayLevels to a nonzero value then the
- printer will be asked to print its halftone with cells containing
- grayLevels-1 printer pixels, yielding the specified number of gray
- levels. E.g. you might want to force your 300 dpi LaserWriter to use big
- cells yielding 256 gray levels.
- Here's a minimal example:
-
- WindowToEPS(window,"test.eps",&rect,&pageRect,0.0,0,NULL);
-
- To print a screen to disk, preserving the size and scale of the
- image, try this:
-
- pageRect=window->portRect;
- pageRect.top*=-1; // convert from Apple to Adobe coordinates
- pageRect.bottom*=-1; // convert from Apple to Adobe coordinates
- SetRect(&paperRect,0,11*72,8.5*72,0);
- CenterRectInRect(&pageRect,&paperRect);
- WindowToEPS(window,"test.eps",&window->portRect,&pageRect,0,0,NULL);
-
- Tiling is something we often want to do, creating a huge image by
- taping many pages together. Simply import your EPS file into a good
- graphics program, e.g. PageMaker, and print with tiling.
-
- REFERENCES
-
- Adobe Systems (1985) PostScript Language Reference Manual, Second Edition.
- Reading, MA: Addison-Wesley.
-
- Pelli, D. G. (1987) Programming in PostScript: Imaging on paper from a mathematical
- description. BYTE, 12 (5), 185-202.
-
- HISTORY:
- 4/21/91 dgp wrote it
- 7/24/91 dgp added comment about shifting pageRect
- 8/24/91 dgp Made compatible with THINK C 5.0
- 12/7/91 dgp minor editing of comments
- 10/10/92 dgp Added support for Pixmap's that require 32-bit addressing.
- Much faster now, using table-lookup instead of sprintf for
- the hex encoding.
- Deleted obsolete support for THINK C 4.
- 4/29/93 dgp & jas Added explanation of how to do tiling.
- 5/27/93 dgp minor editing for speed and clarity
- 6/15/93 dgp Fixed silly bug introduced 5/27/93 that suppressed all hex data.
- Call StripAddress.
- 6/29/93 dgp Changed call interface to accept a pixmap handle instead of a pointer.
- The problem with accepting a pointer is that the user must remember
- to lock the handle before dereferencing it to get the pointer, and
- lots of people forget, leading to a mysterious crash. Now the locking
- is handled internally, automatically.
- 6/30/93 dgp Added example, above, showing how to print screen to disk.
- 7/9/93 dgp check for 32-bit addressing capability.
- 12/15/93 dgp added filename argument to the diagnostic messages.
- Corrected grayLevels to grayLevels-1 in computing
- the required number of pixels in the halftone cell.
- 6/18/94 dgp can32 is now computed by calling TrapAvailable(_SwapMMUMode), which
- returns the correct answer even on Macs with dirty ROMs.
- 9/5/94 dgp removed assumption in printf's that int==short.
- */
- #include "VideoToolbox.h"
- #include <assert.h>
- #include <math.h>
- #include <Traps.h> // _SwapMMUMode
- #define CREATOR 'R*ch' /* for BBEdit */
-
- void WindowToEPS(CWindowPtr window,char *filename,Rect *rectPtr
- ,Rect *pageRectPtr,double cellsPerInch,int grayLevels,float reflectance[256])
- {
- PixMap **pm;
- FILE *file;
- unsigned char *addr;
- long y,bytes,width;
- register long i;
- unsigned short *buffer,*buffer32;
- register unsigned short *word,hex[256];
- register unsigned char *byte;
- short pixelSize;
- short rowBytes;
- time_t ANSITime;
- char string[100];
- char mode,pmState;
- static Boolean can32,is32,firstTime=1;
- long gestalt;
- int ok;
-
- assert(StackSpace()>5000);
- if(firstTime){
- Gestalt(gestaltAddressingModeAttr,&gestalt);
- is32=gestalt&(1<<gestalt32BitAddressing);
- can32=TrapAvailable(_SwapMMUMode);
- firstTime=0;
- }
- if(IsGWorldPtr(window)){
- // It's a GWorldPtr, lock the pixels.
- ok=LockPixels(GetGWorldPixMap((GWorldPtr)window));
- if(!ok)PrintfExit("%s: can't LockPixels on GWorld.\n",__FILE__);
- pm=GetGWorldPixMap((GWorldPtr)window);
- }else if(window->portVersion<0){ // Is it a CGrafPort or a GrafPort?
- // It's a CGrafPort.
- pm=window->portPixMap;
- }else{
- // It's a GrafPort.
- PrintfExit("%s: source must be GWorld or color Window.\n",__FILE__);
- }
- if(cellsPerInch!=0.0 && grayLevels!=0.0)PrintfExit("%s(%s): "
- "you may not specify BOTH cellsPerInch & grayLevels.\n"
- "Set one to zero.\n",__FILE__,filename);
- file=fopen(filename,"w");
- if(file==NULL)PrintfExit("%s: Error in opening file “%s”.\n"
- ,__FILE__,filename);
- pmState=HGetState((Handle)pm);
- HLock((Handle)pm);
- addr=RectToAddress(*pm,rectPtr,&rowBytes,&pixelSize,NULL);
- if(addr==NULL)PrintfExit("%s(%s): Bad PixMap.\n",__FILE__,filename);
- if(pixelSize!=8)PrintfExit("%s(%s): "
- "Sorry, pixelSize must be 8, not %d.\n",__FILE__,filename,(int)pixelSize);
- time(&ANSITime);
- strftime(string,sizeof(string),"%I:%M %p %A, %B %d, %Y",localtime(&ANSITime));
- fprintf(file,
- "%%!PS-Adobe-2.0 EPSF-1.2\n");
- fprintf(file,
- "%%%%Creator:%s\n",IdentifyApplication());
- fprintf(file,
- "%%%%For:%s\n",IdentifyOwner());
- fprintf(file,
- "%%%%Title:%s\n",filename);
- fprintf(file,
- "%%%%CreationDate:%s\n",string);
- fprintf(file,
- "%%%%Pages: 0\n"
- "%%%%BoundingBox:%d %d %d %d\n"
- ,(int)pageRectPtr->left,(int)pageRectPtr->bottom
- ,(int)pageRectPtr->right,(int)pageRectPtr->top);
- fprintf(file,
- "%%%%EndComments\n"
- "%%%%BeginProlog\n"
- "%%%%EndProlog\n"
- "%%%%BeginSetup\n"
- "/VideoToolbox dup 25 dict def load begin\n"
- "end\n"
- "VideoToolbox begin\n"
- "gsave\n"
- "%%%%EndSetup\n");
- fprintf(file,
- "/nx %d def %% pixels per raster line\n",(int)(rectPtr->right-rectPtr->left));
- fprintf(file,
- "/ny %d def %% lines in image\n",(int)(rectPtr->bottom-rectPtr->top));
- fprintf(file,
- "/hypotenuse {dup mul exch dup mul add sqrt} bind def\n"
- "/pixelsPerInch gsave initmatrix 72 0 dtransform hypotenuse grestore def\n"
- "%d %d translate %% locate lower left of image\n"
- ,(int)pageRectPtr->left,(int)pageRectPtr->bottom);
- fprintf(file,
- "%d %d scale %% print image with these dimensions on page\n"
- ,(int)(pageRectPtr->right-pageRectPtr->left),(int)(pageRectPtr->top-pageRectPtr->bottom));
- if(cellsPerInch!=0.0){
- fprintf(file,
- "/cellsPerInch %.2f def %% halftone dot frequency\n",cellsPerInch);
- fprintf(file,
- "cellsPerInch currentscreen 4 -2 roll pop 3 1 roll setscreen\n");
- }
- if(grayLevels!=0){
- fprintf(file,
- "/cellsPerInch pixelsPerInch %.2f div def %% halftone dot frequency\n"
- ,sqrt(grayLevels-1));
- fprintf(file,
- "cellsPerInch currentscreen 4 -2 roll pop 3 1 roll setscreen\n");
- }
- fprintf(file,
- "/s nx string def %% string to hold one raster line\n"
- "nx ny 8 %% dimensions and bits/pixel of source image\n"
- "[nx 0 0 ny neg 0 ny] %% map unit square to PixMap data\n"
- "{currentfile s readhexstring pop} %% read data\n"
- "bind %% speed up reading\n"
- "image\n");
- assert(sizeof(*byte)==1); // required by our algorithm
- assert(sizeof(*word)==2); // required by our algorithm
- if(reflectance==NULL)for(i=0;i<256;i++){
- sprintf(string,"%02x",(int)i);
- hex[i]=*(unsigned short *)string;
- }else for(i=0;i<256;i++){
- int j;
- j=0.5+255*reflectance[i];
- if(j<0)j=0;
- if(j>255)j=255;
- sprintf(string,"%02x",j);
- hex[i]=*(unsigned short *)string;
- }
- width=rectPtr->right-rectPtr->left;
- bytes=(width+1)*sizeof(*word);
- buffer=(unsigned short *)NewPtr(bytes);
- if(buffer==NULL)PrintfExit("%s(%s): "
- "no room for %ld byte buffer.\n\007",__FILE__,filename,bytes);
- buffer32=(unsigned short *)StripAddress(buffer);
- for(y=rectPtr->top;y<rectPtr->bottom;y++){
- mode=true32b;
- if(can32)SwapMMUMode(&mode);
- byte=addr;
- word=buffer32;
- for(i=0;i<width;i++) *word++ = hex[*byte++];
- *word=0;
- if(can32)SwapMMUMode(&mode);
- fprintf(file,"%s\n",(char *)buffer);
- addr+=rowBytes;
- }
- HSetState((Handle)pm,pmState);
- DisposPtr((Ptr)buffer);
- fprintf(file,
- "%%%%Trailer\n"
- "grestore\n"
- "end\n"
- "showpage\n"
- "%%%%EOF\n");
- fclose(file);
- SetFileInfo(filename,'TEXT',CREATOR);
- }
-